package com.example.project.service.impl;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import org.apache.commons.compress.utils.Lists;
import org.apache.commons.lang3.SerializationUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.message.service.MessageService;
import com.example.project.annotation.FieldMeta;
import com.example.project.annotation.IssueOperation;
import com.example.project.core.text.Convert;
import com.example.project.entity.Attachment;
import com.example.project.entity.Issue;
import com.example.project.entity.IssuePrioritie;
import com.example.project.entity.IssueStatus;
import com.example.project.entity.Journal;
import com.example.project.entity.JournalDetail;
import com.example.project.entity.Project;
import com.example.project.entity.Tracker;
import com.example.project.entity.User;
import com.example.project.mapper.IssueMapper;
import com.example.project.service.AttachmentService;
import com.example.project.service.CommonService;
import com.example.project.service.IssueOperationRecordService;
import com.example.project.service.IssueService;
import com.example.project.service.JournalDetailService;
import com.example.project.service.JournalService;
import com.example.project.service.WatcherService;
import com.example.project.utils.CacheUtils;
import com.example.project.utils.DateUtils;
import com.example.project.utils.EntityUtil;
import com.example.project.utils.NumberConvertUtil;
import com.example.project.utils.StringUtils;

/**
 * 问题，存储项目中的任务、缺陷等问题Service业务层处理
 * 
 * @author ruoyi
 * @date 2025-09-19
 */
@Service
public class IssueServiceImpl extends BaseServiceImpl implements IssueService {

	@Autowired
	private CommonService commonService;

	@Autowired
	private IssueMapper issuesMapper;

	@Autowired
	private JournalService journalService;

	@Autowired
	private AttachmentService attachmentService;

	@Autowired
	private JournalDetailService journalDetailService;

	@Autowired
	private MessageService messageService;

	@Autowired
	private IssueOperationRecordService issueOperationRecordService;


	/**
	 * 通过ID获取问题信息，支持缓存优化
	 * 适用于在循环中重复查询同一ID的场景
	 * 采用单条记录缓存策略，避免缓存整个问题列表
	 *
	 * @param issueId 问题ID
	 * @return 问题对象，如果不存在返回null
	 */
	@Override
	public Issue getIssueInfoForCache(Long issueId) {
		if (issueId == null) {
			return null;
		}
		
		// 先从缓存中获取单个问题
		String cacheKey = "issue_" + issueId;
		Issue issue = (Issue) CacheUtils.get("issue-cache", cacheKey);
		
		if (issue == null) {
			// 如果缓存中不存在，从数据库查询
			issue = this.selectIssuesById(issueId);
			if (issue != null) {
				// 转换为完整信息
				issue = this.convertToIssuesInfo(issue);
				// 缓存单个问题，使用专门的issue-cache缓存（5分钟过期）
				CacheUtils.put("issue-cache", cacheKey, issue);
			}
		}
		
		return issue;
	}

	/**
	 * 查询问题，存储项目中的任务、缺陷等问题
	 * 
	 * @param id 问题，存储项目中的任务、缺陷等问题主键
	 * @return 问题，存储项目中的任务、缺陷等问题
	 */
	@Override
	public Issue selectIssuesById(Long id) {
		Issue issues = issuesMapper.selectIssuesById(id);
		if (issues != null) {
			return convertToIssuesInfo(issues);
		}
		return issues;
	}

	@Override
	public long getCount(Issue issue) {
		// TODO Auto-generated method stub
		return issuesMapper.getCount(issue);
	}

	@Override
	public long getTodayCount() {
		return issuesMapper.getTodayCount();
	}

	/**
	 * 将Issues转换为IssuesInfo
	 */
	@Override
	public List<Issue> convertToIssuesList(List<Issue> issueList) {
		if (!issueList.isEmpty()) {
			// 跟踪类型名称
			Map<Long, Tracker> trackerMap = commonService.getTrackerMap();

			// 项目名称
			Map<Long, Project> projectMap = commonService.getProjectMap();

			// 状态名称
			Map<Long, IssueStatus> statusMap = commonService.getIssueStatusMap();

			Map<Long, User> userMap = commonService.getUserMap();

			// 优先级
			Map<Long, IssuePrioritie> issuePrioritieMap = commonService.getIssuePrioritieMap();

			issueList.forEach(info -> {
				// 查询并设置额外字段
				// 跟踪类型名称
				if (info.getTrackerId() != null) {
					Tracker tracker = trackerMap.get(info.getTrackerId());
					info.setTrackerName(tracker != null ? tracker.getName() : "");
					info.setTracker(tracker);
				}

				// 项目名称
				if (info.getProjectId() != null) {
					Project project = projectMap.get(info.getProjectId());
					info.setProjectName(project != null ? project.getName() : "");
					info.setProject(project);
				}

				// 状态名称
				if (info.getStatusId() != null) {
					IssueStatus issueStatus = statusMap.get(info.getStatusId());
					info.setStatusName(issueStatus != null ? issueStatus.getName() : "");
					info.setIssueStatus(issueStatus);
				}

				// 优先级名称（根据ID映射）
				if (info.getPriorityId() != null) {
					IssuePrioritie priority = issuePrioritieMap.get(info.getPriorityId());
					info.setPriorityName(priority != null ? priority.getName() : "");
					info.setPriority(priority);
				}

				// 指派给用户名称
				Long assignedToId = info.getAssignedToId();
				if (assignedToId != null && assignedToId != 0L) {
					User user = userMap.get(assignedToId);
					info.setAssignedToName(user != null ? user.getUserName() : "");
				}
				// 作者名称
				Long authorId = info.getAuthorId();
				if (authorId != null && authorId != 0L) {
					User user = userMap.get(authorId);
					info.setAuthorName(user != null ? user.getUserName() : "");
				}
			});
		}
		return issueList;
	}

	/**
	 * 将Issues转换为IssuesInfo
	 */
	@Override
	public Issue convertToIssuesInfo(Issue issue) {
		// 查询并设置额外字段
		// 跟踪类型名称
		if (issue.getTrackerId() != null) {
			Map<Long, Tracker> trackerMap = commonService.getTrackerMap();
			Tracker tracker = trackerMap.get(issue.getTrackerId());
			if (tracker != null) {
				issue.setTrackerName(tracker.getName());
				issue.setTracker(tracker);
			}
		}

		// 项目名称
		if (issue.getProjectId() != null) {
			Map<Long, Project> projectMap = commonService.getProjectMap();
			Project project = projectMap.get(issue.getProjectId());
			if (project != null) {
				issue.setProjectName(project.getName());
				issue.setProject(project);
			}
		}

		// 状态名称
		if (issue.getStatusId() != null) {
			Map<Long, IssueStatus> issueStatusMap = commonService.getIssueStatusMap();
			IssueStatus status = issueStatusMap.get(issue.getStatusId());
			if (status != null) {
				issue.setStatusName(status.getName());
				issue.setIssueStatus(status);
			}
		}

		// 优先级名称（根据ID映射）
		if (issue.getPriorityId() != null) {
			Map<Long, IssuePrioritie> issuePrioritieMap = commonService.getIssuePrioritieMap();
			IssuePrioritie priority = issuePrioritieMap.get(issue.getPriorityId());
			issue.setPriorityName(priority != null ? priority.getName() : "低");
			issue.setPriority(priority);
		}

		Map<Long, User> userMap = commonService.getUserMap();
		// 指派给用户名称
		Long assignedToId = issue.getAssignedToId();
		if (assignedToId != null && assignedToId != 0L) {
			User assignedUser = userMap.get(assignedToId);
			if (assignedUser != null) {
				issue.setAssignedToName(assignedUser.getUserName());
			} else if (assignedToId == 1) {
				issue.setAssignedToName("管理员");
			}
		}
		// 领取人
		Long recipient = issue.getRecipient();
		if (recipient != null && recipient != 0L) {
			User user = userMap.get(recipient);
			issue.setRecipientName(user != null ? user.getUserName() : recipient == 1L ? "管理员" : "无");
		}

		// 作者名称
		Long authorId = issue.getAuthorId();
		if (authorId != null && authorId != 0L) {
			User authorUser = userMap.get(authorId);
			if (authorUser != null) {
				issue.setAuthorName(authorUser.getUserName());
			} else if (authorId == 1L) {
				issue.setAuthorName("管理员");
			}
		}

		Map<String, User> userLoginMap = commonService.getUserMapByLoginName();
		String createBy = issue.getCreateBy();
		if (StringUtils.isNotEmpty(createBy)) {
			User user = userLoginMap.get(createBy);
			if (user == null && NumberConvertUtil.isNumeric(createBy)) {
				user = userMap.get(NumberConvertUtil.safeParseLong(createBy, 0L));
			}
			if (user != null) {
				issue.setCreateUser(user.getUserName());
			}
		}
		return issue;
	}

	/**
	 * 查询问题，存储项目中的任务、缺陷等问题列表
	 * 
	 * @param issue 问题，存储项目中的任务、缺陷等问题
	 * @return 问题，存储项目中的任务、缺陷等问题
	 */
	@Override
	public List<Issue> selectIssuesList(Issue issue) {
		Page<Issue> page = new Page<>(1, Integer.MAX_VALUE);
		List<Issue> lists = issuesMapper.selectIssuesList(page, issue);
		return lists;
	}

	/**
	 * 新增问题，存储项目中的任务、缺陷等问题
	 * 
	 * @param issues 问题，存储项目中的任务、缺陷等问题
	 * @return 结果
	 */
	@Override
	public long insertIssues(Issue issues) {
		issues.setCreateTime(DateUtils.curLocalDateTime());
		// 整理 estimatedHours 字段
		issues.setEstimatedHours(DateUtils.formatEstimatedHours(issues.getEstimatedHours()));
		long result = issuesMapper.insertIssues(issues);

		// 记录发布需求操作
		if (result > 0) {
			publishRequirement(issues.getId());
		}

		return result;
	}

	/**
	 * 发布需求
	 */
	@IssueOperation(type = 3, value = "发布了需求")
	public void publishRequirement(Long issueId) {
		// 空实现，操作由AOP切面记录
	}

	/**
	 * 修改问题，存储项目中的任务、缺陷等问题
	 * 
	 * @param issue 问题，存储项目中的任务、缺陷等问题
	 * @return 结果
	 */
	@Override
	public int updateIssues(Issue issue, String uploadedFilesJson) {
		Issue info = issuesMapper.selectIssuesById(issue.getId());
		if (info == null) {
			// 不存在
			return -1;
		}

		// 保存原始数据用于比较变更
		Issue originalIssue = SerializationUtils.clone(info);

		// 设置更新信息
		issue.setUpdateBy(getLoginName());
		issue.setUpdateTime(DateUtils.curLocalDateTime());
		// 整理 estimatedHours 字段
		issue.setEstimatedHours(DateUtils.formatEstimatedHours(issue.getEstimatedHours()));

		// 检查是否有字段变动或文件上传
		String[] filter = { "projectId", "trackerId", "subject", "statusId", "startDate", "priorityId", "dueDate",
				"assignedToId", "estimatedHours", "categoryId", "doneRatio", "description", "recipient" };
		boolean hasFieldChanges = EntityUtil.queryContrastObjStatus(originalIssue, issue, Issue.class, filter);
		boolean hasFileUpload = StringUtils.isNotEmpty(uploadedFilesJson) && !"[]".equals(uploadedFilesJson);
		boolean hasNotesChanges = StringUtils.isNotEmpty(issue.getNotes());

		// 如果没有字段变动且没有文件上传，直接返回0
		if (!hasFieldChanges && !hasFileUpload && !hasNotesChanges) {
			return 2;
		}

		int result = issuesMapper.updateIssues(issue);

		// 如果更新成功，记录变更历史
		if (result > 0) {
			List<Attachment> attachmentList = Lists.newArrayList();
			if (uploadedFilesJson != null && !uploadedFilesJson.isEmpty()) {
				attachmentList = attachmentService.saveAttachments(issue.getId(), uploadedFilesJson);
			}

			Journal journal = insertJournal(originalIssue, issue, issue.getNotes());

			if (journal != null && journal.getId() != null && journal.getId() > 0) {
				// 插入JournalDetail记录
				insertJournalDetails(journal.getId(), originalIssue, issue);

				if (!attachmentList.isEmpty()) {
					attachmentList.forEach(attachment -> {
						insertJournalDetail(journal.getId(), "attachment", "file_path", attachment.getFilename(), "",
								attachment.getId());
					});
				}
			}
			// 发送消息
			Issue issueInfo = convertToIssuesInfo(issue);
			messageService.sendIssueMessage(issueInfo);
		}

		return result;
	}

	/**
	 * 批量删除问题，存储项目中的任务、缺陷等问题
	 * 
	 * @param ids 需要删除的问题，存储项目中的任务、缺陷等问题主键
	 * @return 结果
	 */
	@Override
	public int deleteIssuesByIds(String ids) {
		return issuesMapper.deleteIssuesByIds(Convert.toStrArray(ids));
	}

	/**
	 * 删除问题，存储项目中的任务、缺陷等问题信息
	 * 
	 * @param id 问题，存储项目中的任务、缺陷等问题主键
	 * @return 结果
	 */
	@Override
	public int deleteIssuesById(Long id) {
		return issuesMapper.deleteIssuesById(id);
	}

	/**
	 * 插入Journal和JournalDetail记录
	 * 
	 * @param notes
	 */
	private Journal insertJournal(Issue original, Issue updated, String notes) {
		// 获取当前用户ID
		Long currentUserId = getUserId();

		// 创建Journal记录
		Journal journal = new Journal("Issue", updated.getId(), currentUserId);
		journal.setNotes(notes);
		journal.setPrivateNotes(0); // 公开笔记
		journal.setCreatedOn(DateUtils.curLocalDateTime());
		journal.setUpdatedOn(DateUtils.curLocalDateTime());
		journal.setUpdatedById(currentUserId);

		// 插入Journal记录
		journalService.insertJournals(journal);
		return journal;
	}

	/**
	 * 插入JournalDetail记录
	 */
	private void insertJournalDetails(Long journalId, Issue original, Issue updated) {
		// 比较各个字段并插入变更详情
		Class<?> className = Issue.class;
		try {
			Field[] fields = Issue.class.getDeclaredFields();
			for (Field field : fields) {
				String variableName = field.getName();
				String[] filter = { "projectId", "trackerId", "subject", "description", "statusId", "startDate",
						"priorityId", "dueDate", "assignedToId", "estimatedHours", "categoryId", "doneRatio" };
				// 过滤：只包含指定的字段
				boolean searchContains = !Arrays.asList(filter).contains(variableName);
				if (searchContains) {
					continue;
				}
				if ("serialVersionUID".equals(variableName)) {
					continue;
				}
				String description = "";
				String fieldName = "";
				FieldMeta annotation = field.getAnnotation(FieldMeta.class);
				if (null != annotation) {
					description = annotation.description();
					fieldName = annotation.name();
				}
				PropertyDescriptor pd = new PropertyDescriptor(variableName, className);
				Method getMethod = pd.getReadMethod();
				Object o1 = getMethod.invoke(original);
				Object o2 = getMethod.invoke(updated);
				insertJournalDetail(journalId, "attr", variableName, description, o1, o2);

			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 如果字段有变更，插入JournalDetail记录
	 */
	private void insertJournalDetail(Long journalId, String property, String propKey, String description,
			Object oldValue, Object newValue) {
		if (!Objects.equals(oldValue, newValue)) {
			try {
				JournalDetail detail = new JournalDetail();
				detail.setJournalId(journalId);
				detail.setProperty(property);
				detail.setPropKey(propKey);
				detail.setDescription(description);
				detail.setOldValue(String.valueOf(oldValue));
				detail.setValue(String.valueOf(newValue));

				journalDetailService.insertJournalDetails(detail);
			} catch (Exception e) {
				System.err.println("插入JournalDetail记录失败: " + e.getMessage());
			}
		}
	}

	@Override
	public List<Issue> findListByAssignedToIdOrderByTimeDesc(Long userId) {
		// TODO Auto-generated method stub
		return issuesMapper.findListByAssignedToId(userId);
	}

	@Override
	public List<Issue> findListByCondition(Issue issue) {
		// 使用现有的selectIssuesList方法进行条件查询
		List<Issue> issueList = selectIssuesList(issue);
		convertToIssuesList(issueList);

		return issueList;
	}

	@Override
	public List<Map<String, Object>> findTotalGroupByProjectId() {
		// TODO Auto-generated method stub
		return issuesMapper.findTotalGroupByProjectId();
	}

	@Override
	public List<Map<String, Object>> findListGroupByMonth() {
		// TODO Auto-generated method stub
		return issuesMapper.findListGroupByMonth();
	}

	@Override
	public List<Issue> findListByConditionWithLimit(Issue issue, int limit) {
		// 使用分页查询限制数量
		List<Issue> issueList = issuesMapper.findListByConditionWithLimit(issue, limit);

		// 对每个问题进行信息转换
		for (Issue item : issueList) {
			convertToIssuesInfo(item);
		}

		return issueList;
	}

	@Override
	public List<Map<String, Object>> selectIssueStatusTotal() {
		// TODO Auto-generated method stub
		return issuesMapper.selectIssueStatusTotal();
	}

	@Override
	public int setupAssignedToId(Issue issue, Long userId, Long statusId) {
		// TODO Auto-generated method stub
		if (issue != null) {
			// 获取操作前的状态
			Long oldStatusId = issue.getStatusId();
			Long oldAssignedToId = issue.getAssignedToId();

			// 更新状态和指派人
			issue.setStatusId(statusId);
			issue.setAssignedToId(userId);
			int result = this.updateIssues(issue, null);

			// 根据状态变化确定操作类型并调用对应的注解方法
			if (result > 0) {
				// 领取需求：状态从新建(1)变为进行中(2)
				if (oldStatusId != null && oldStatusId == 1 && statusId == 2) {
					issueOperationRecordService.claimRequirement(issue.getId());
				}
				// 完成需求：状态从进行中(2)变为待测试(3)
				else if (oldStatusId != null && oldStatusId == 2 && statusId == 3) {
					issueOperationRecordService.completeRequirement(issue.getId());
				}
				// 审核通过：状态从待测试(3)变为已解决(4)
				else if (oldStatusId != null && oldStatusId == 3 && statusId == 4) {
					issueOperationRecordService.approveRequirement(issue.getId());
				}
				// 审核不通过：状态从待测试(3)变为重新打开(5)
				else if (oldStatusId != null && oldStatusId == 3 && statusId == 5) {
					issueOperationRecordService.rejectRequirement(issue.getId());
				}
			}

			return result;
		}
		return 0;
	}

}
